#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
B站弹幕机 JMeter 测试结果简单分析脚本
作者: AI Assistant
版本: 1.0
"""

import pandas as pd
import matplotlib.pyplot as plt
import json
import os
import sys
from datetime import datetime

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

def load_data(result_file='test_results.jtl'):
    """加载JMeter测试结果数据"""
    try:
        if not os.path.exists(result_file):
            print(f"错误: 测试结果文件不存在: {result_file}")
            return None
            
        df = pd.read_csv(result_file)
        
        # 处理时间戳列 - 将毫秒时间戳转换为datetime
        if 'timeStamp' in df.columns:
            df['timeStamp'] = pd.to_datetime(df['timeStamp'], unit='ms')
        
        # 确保success列是布尔类型
        if 'success' in df.columns:
            df['success'] = df['success'].astype(bool)
        
        print(f"成功加载测试数据，共 {len(df)} 条记录")
        print(f"时间范围: {df['timeStamp'].min()} 到 {df['timeStamp'].max()}")
        return df
    except Exception as e:
        print(f"加载数据失败: {e}")
        return None

def basic_statistics(df):
    """基础统计分析"""
    if df is None or len(df) == 0:
        return None
        
    # 计算测试持续时间
    test_duration = (df['timeStamp'].max() - df['timeStamp'].min()).total_seconds()
    
    stats = {
        '总请求数': len(df),
        '成功请求数': len(df[df['success'] == True]),
        '失败请求数': len(df[df['success'] == False]),
        '平均响应时间(ms)': df['elapsed'].mean(),
        '最小响应时间(ms)': df['elapsed'].min(),
        '最大响应时间(ms)': df['elapsed'].max(),
        '95%响应时间(ms)': df['elapsed'].quantile(0.95),
        '99%响应时间(ms)': df['elapsed'].quantile(0.99),
        '标准差(ms)': df['elapsed'].std(),
        '测试持续时间(秒)': test_duration,
        '吞吐量(请求/秒)': len(df) / test_duration if test_duration > 0 else 0
    }
    
    # 计算成功率
    stats['成功率(%)'] = (stats['成功请求数'] / stats['总请求数']) * 100
    
    return stats

def generate_simple_charts(df, output_dir='analysis_results'):
    """生成简单的分析图表"""
    if df is None or len(df) == 0:
        print("警告: 没有数据可以生成图表")
        return
    
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    
    # 创建图表
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    
    # 1. 响应时间分布直方图
    axes[0, 0].hist(df['elapsed'], bins=30, alpha=0.7, color='skyblue', edgecolor='black')
    axes[0, 0].set_title('响应时间分布')
    axes[0, 0].set_xlabel('响应时间 (ms)')
    axes[0, 0].set_ylabel('请求数量')
    axes[0, 0].grid(True, alpha=0.3)
    
    # 2. 成功/失败请求分布饼图
    success_counts = df['success'].value_counts()
    axes[0, 1].pie(success_counts, labels=['成功' if x else '失败' for x in success_counts.index], 
                   autopct='%1.1f%%', startangle=90)
    axes[0, 1].set_title('请求成功/失败分布')
    
    # 3. 各接口平均响应时间柱状图
    interface_means = df.groupby('label')['elapsed'].mean()
    if len(interface_means) > 0:
        axes[1, 0].bar(range(len(interface_means)), interface_means)
        axes[1, 0].set_title('各接口平均响应时间')
        axes[1, 0].set_xlabel('接口')
        axes[1, 0].set_ylabel('平均响应时间 (ms)')
        axes[1, 0].set_xticks(range(len(interface_means)))
        axes[1, 0].set_xticklabels(interface_means.index, rotation=45, ha='right')
        axes[1, 0].grid(True, alpha=0.3)
    
    # 4. 各接口请求数量柱状图
    interface_counts = df['label'].value_counts()
    if len(interface_counts) > 0:
        axes[1, 1].bar(range(len(interface_counts)), interface_counts)
        axes[1, 1].set_title('各接口请求数量')
        axes[1, 1].set_xlabel('接口')
        axes[1, 1].set_ylabel('请求数量')
        axes[1, 1].set_xticks(range(len(interface_counts)))
        axes[1, 1].set_xticklabels(interface_counts.index, rotation=45, ha='right')
        axes[1, 1].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig(f'{output_dir}/simple_analysis.png', dpi=300, bbox_inches='tight')
    plt.close()
    
    print(f"简单分析图表已保存: {output_dir}/simple_analysis.png")

def generate_report(df, stats, output_dir='analysis_results'):
    """生成分析报告"""
    if df is None:
        return
    
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    
    # 转换stats中的numpy类型为Python原生类型
    converted_stats = {}
    for key, value in stats.items():
        if hasattr(value, 'item'):  # numpy类型
            converted_stats[key] = value.item()
        else:
            converted_stats[key] = value
    
    # 生成JSON报告
    report = {
        '测试信息': {
            '测试时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            '数据记录数': len(df)
        },
        '基础统计': converted_stats,
        '接口分析': {}
    }
    
    # 各接口详细分析
    for interface in df['label'].unique():
        interface_data = df[df['label'] == interface]
        report['接口分析'][interface] = {
            '请求数量': int(len(interface_data)),
            '成功数量': int(len(interface_data[interface_data['success'] == True])),
            '失败数量': int(len(interface_data[interface_data['success'] == False])),
            '成功率(%)': float(round(len(interface_data[interface_data['success'] == True]) / len(interface_data) * 100, 2)),
            '平均响应时间(ms)': float(round(interface_data['elapsed'].mean(), 2)),
            '最小响应时间(ms)': float(interface_data['elapsed'].min()),
            '最大响应时间(ms)': float(interface_data['elapsed'].max()),
            '95%响应时间(ms)': float(round(interface_data['elapsed'].quantile(0.95), 2))
        }
    
    # 保存JSON报告
    with open(f'{output_dir}/simple_report.json', 'w', encoding='utf-8') as f:
        json.dump(report, f, ensure_ascii=False, indent=2)
    
    # 生成HTML报告
    html_content = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>B站弹幕机 JMeter 测试报告</title>
    <style>
        body {{ font-family: 'Microsoft YaHei', Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }}
        .container {{ max-width: 1200px; margin: 0 auto; background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
        h1 {{ color: #333; text-align: center; border-bottom: 2px solid #007bff; padding-bottom: 10px; }}
        h2 {{ color: #007bff; margin-top: 30px; }}
        .stats-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; }}
        .stat-card {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 8px; text-align: center; }}
        .stat-value {{ font-size: 24px; font-weight: bold; margin: 5px 0; }}
        .stat-label {{ font-size: 14px; opacity: 0.9; }}
        table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
        th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
        th {{ background-color: #f8f9fa; font-weight: bold; }}
        tr:hover {{ background-color: #f5f5f5; }}
        .success {{ color: #28a745; }}
        .warning {{ color: #ffc107; }}
        .danger {{ color: #dc3545; }}
        .chart-container {{ margin: 20px 0; text-align: center; }}
        .chart-container img {{ max-width: 100%; height: auto; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }}
    </style>
</head>
<body>
    <div class="container">
        <h1>B站弹幕机 JMeter 测试报告</h1>
        
        <h2>测试信息</h2>
        <table>
            <tr><th>测试时间</th><td>{report['测试信息']['测试时间']}</td></tr>
            <tr><th>数据记录数</th><td>{report['测试信息']['数据记录数']}</td></tr>
        </table>
        
        <h2>基础统计</h2>
        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['总请求数']}</div>
                <div class="stat-label">总请求数</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['成功请求数']}</div>
                <div class="stat-label">成功请求数</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['失败请求数']}</div>
                <div class="stat-label">失败请求数</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['成功率(%)']:.1f}%</div>
                <div class="stat-label">成功率</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['平均响应时间(ms)']:.1f}ms</div>
                <div class="stat-label">平均响应时间</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{report['基础统计']['吞吐量(请求/秒)']:.1f}/s</div>
                <div class="stat-label">吞吐量</div>
            </div>
        </div>
        
        <h2>接口详细分析</h2>
        <table>
            <thead>
                <tr>
                    <th>接口名称</th>
                    <th>请求数量</th>
                    <th>成功数量</th>
                    <th>失败数量</th>
                    <th>成功率</th>
                    <th>平均响应时间</th>
                    <th>95%响应时间</th>
                </tr>
            </thead>
            <tbody>
"""
    
    for interface, data in report['接口分析'].items():
        success_class = 'success' if data['成功率(%)'] >= 95 else 'warning' if data['成功率(%)'] >= 80 else 'danger'
        html_content += f"""
                <tr>
                    <td>{interface}</td>
                    <td>{data['请求数量']}</td>
                    <td>{data['成功数量']}</td>
                    <td>{data['失败数量']}</td>
                    <td class="{success_class}">{data['成功率(%)']}%</td>
                    <td>{data['平均响应时间(ms)']}ms</td>
                    <td>{data['95%响应时间(ms)']}ms</td>
                </tr>
"""
    
    html_content += """
            </tbody>
        </table>
        
        <h2>分析图表</h2>
        <div class="chart-container">
            <img src="simple_analysis.png" alt="简单分析图表">
        </div>
    </div>
</body>
</html>
"""
    
    with open(f'{output_dir}/simple_report.html', 'w', encoding='utf-8') as f:
        f.write(html_content)
    
    print(f"简单报告已保存: {output_dir}/simple_report.json")
    print(f"HTML报告已保存: {output_dir}/simple_report.html")

def main():
    """主函数"""
    print("开始分析JMeter测试结果...")
    
    # 加载数据
    df = load_data()
    if df is None:
        print("分析失败！")
        sys.exit(1)
    
    # 基础统计
    stats = basic_statistics(df)
    if stats:
        print("\n=== 基础统计 ===")
        for key, value in stats.items():
            print(f"{key}: {value}")
    
    # 生成图表
    print("\n生成分析图表...")
    generate_simple_charts(df)
    
    # 生成报告
    print("\n生成详细报告...")
    generate_report(df, stats)
    
    print(f"\n分析完成！结果保存在 analysis_results 目录中")

if __name__ == '__main__':
    main() 